//
// Created by dguco on 20-1-11.
//

#include "unit_test.h"
#include <map>
#include "game_util/rankskip_list.h"
#include "su_rand.h"
#include "game_util/sorted_set.h"
#include "easy_code.h"

using namespace su;



class member
{
public:
	inline static uint32 s_num = 0;

	int id;
	int chinese;
	int math;
	int english;
    member()
    {
        id = -1;
        chinese = 0;
        math = 0;
        english = 0;
		s_num++;
    }
    member(int id,int chinese, int math, int english)
        : id (id),chinese(chinese), math(math), english(english)
	{
		s_num++;
    }
	member(const member& other)
	{
		s_num++;
		id = other.id;
		chinese = other.chinese;
		math = other.math;
		english = other.english;
	}
	member(const member&& other)
	{
		s_num++;
		id = other.id;
		chinese = other.chinese;
		math = other.math;
		english = other.english;
	}
	member& operator = (const member& other) = default;
	~member()
	{
		s_num--;
	}
    int Sum()
    {
        return chinese + math + english;
    }

    bool operator ==(const member& d)
    {
        return this->id == d.id && this->chinese == d.chinese &&
            this->math == d.math && this->english == d.english;
    }

    bool bless (const member& d)
    {
        int sumMe = chinese + math + english;
        int sumHe = d.chinese + d.math + d.english;
        if (sumMe > sumHe)
        {
            return true;
        }
        else if (sumMe == sumHe)
        {
            if (this->chinese > d.chinese)
            {
                return true;
            }
            else if (this->chinese == d.chinese)
            {
                if (this->math > d.math)
                {
                    return true;
                }
                else if (this->math == d.math)
                {
                    if (this->english > d.english)
                    {
                        return true;
                    }
                    else if (this->english == d.english)
                    {
                        return id > d.id;
                    } else{
                        return false;
                    }
                } else{
                    return false;
                }
            } else{
                return false;
            }
        } else{
            return false;
        }
    }

    bool operator > (const member& d)
    {
        if (*this == d)
        {
            return false;
        }
        return (bless(d));
    }

    int getId() const
    {
        return id;
    }
    int getChinese() const
    {
        return chinese;
    }
    int getMath() const
    {
        return math;
    }

    int getEnglish() const
    {
        return english;
    }
};

namespace
{
	RankSkipList<int, std::pair<int, int>> g_skiplist(5);
}

void test1()
{

	for (auto& v : g_skiplist)
	{
		UNIT_ASSERT(false);
	}
	{
		auto f = [](uint32 rank, const std::pair<int, int>& d)
		{
			UNIT_ASSERT(false);
		};
		g_skiplist.EachValue(f);
	}

    auto *p = g_skiplist.Insert(1, { 1,1 });
	LDEBUG("insert key, score", p->first, p->second, p);
	{
		uint32 cnt = 0;
		auto f = [&](uint32 rank, const std::pair<int, int>& d)
		{
			cnt++;
			LDEBUG("score=", d.second, "key=", d.first, "&d", &d);
			UNIT_ASSERT(rank == cnt);
		};
		g_skiplist.EachValue(f);
		UNIT_ASSERT(cnt == 1);
	}

	g_skiplist.Insert(1, { 1,1 });
	g_skiplist.Insert(2, { 2,2 });
	g_skiplist.Insert(3, { 3,3 });
	g_skiplist.Insert(4, { 4,4 });
	g_skiplist.Insert(5, { 5,5 });
	{
		uint32 cnt = 0;
		int32 lastscore = 888888;
		auto f = [&](uint32 rank, const std::pair<int, int>& d)
		{
			cnt++;
			UNIT_ASSERT(rank == cnt);
			LDEBUG("score=", d.second, "key=", d.first);
			UNIT_ASSERT(d.second < lastscore);
			lastscore = d.second;
		};
		g_skiplist.EachValue(f);
		UNIT_ASSERT(cnt == 5);
	}
	for (auto& v : g_skiplist)
	{
		LDEBUG("auto each score=", v.second, "key=", v.first);
	}

	//查找测试
	{
		const std::pair<int, int>* p = nullptr;
		uint64 rank;
		g_skiplist.Get(1, p, rank);
		UNIT_ASSERT(p->second == 1);
		UNIT_ASSERT(rank == 5);
		rank = g_skiplist.Rank(5);
		UNIT_ASSERT(rank == 1);
		rank = g_skiplist.Rank(4);
		UNIT_ASSERT(rank == 2);
		p = g_skiplist.GetByRank(3);
		UNIT_ASSERT(p->second == 3);
		auto vec = g_skiplist.GetRangeByRank(1, 2);
		UNIT_ASSERT(vec.size() == 2);
		UNIT_ASSERT(vec[0]->second == 5);
		UNIT_ASSERT(vec[1]->second == 4);
		 vec = g_skiplist.GetRangeByRank(0, 1);
		UNIT_ASSERT(vec.size() == 1);
		UNIT_ASSERT(vec[0]->second == 5);
		 vec = g_skiplist.GetRangeByRank(5, 5);
		UNIT_ASSERT(vec.size() == 1);
		UNIT_ASSERT(vec[0]->second == 1);
		 vec = g_skiplist.GetRangeByRank(4, 5);
		UNIT_ASSERT(vec.size() == 2);
		UNIT_ASSERT(vec[0]->second == 2);
		UNIT_ASSERT(vec[1]->second == 1);
	}

}
void test2()
{

	UNIT_INFO("s1 num=%d", member::s_num);
	RankSkipList<int, member> rankkkkk;
	RankSkipList<int, member>* rankSkipList = &rankkkkk;
	UNIT_ASSERT(1 == member::s_num);
	member m[100];
	for (int i = 0; i < 100; i++)
	{
		m[i].id = i;
		m[i].chinese = std::rand() % 100 + 1;
		m[i].math = std::rand() % 100 + 1;
		m[i].english = std::rand() % 100 + 1;
	}
	PrimeRandom prand(100);
	for (int i = 0; i < 100; i++)
	{
		int idx = prand.GetRandom();
		member& d = m[idx];
		rankSkipList->Insert(d.id, d);

	}

	UNIT_ASSERT(201 == member::s_num);
	rankSkipList->Insert(2, member(2, 99, 99, 99));

	rankSkipList->Insert(3, member(3, 10, 29, 39));
	rankSkipList->Insert(4, member(4, 30, 20, 10));
	rankSkipList->Insert(5, member(5, 99, 99, 99));
	rankSkipList->Insert(6, member(6, 100, 98, 98));
	rankSkipList->Insert(7, member(7, 99, 99, 100));
	rankSkipList->Insert(8, member(8, 99, 99, 99));
	rankSkipList->Insert(9, member(9, 90, 90, 90));
	rankSkipList->Insert(10, member(10, 90, 90, 90));
	rankSkipList->Insert(11, member(11, 80, 85, 90));
	rankSkipList->Insert(12, member(12, 90, 80, 85));
	rankSkipList->Insert(13, member(13, 80, 85, 90));
	rankSkipList->Insert(14, member(14, 80, 90, 85));
	UNIT_ASSERT(201 == member::s_num);
	rankSkipList->Insert(101, member(101, 0, 0, 0));
	rankSkipList->Insert(102, member(102, 100, 100, 100));

	UNIT_ASSERT(203 == member::s_num);
	std::map<int, bool> res;
	for (int i = 1; i <= 200; i++)//删除无效id
	{
		int key = 20 + i * 400;
		rankSkipList->Remove(key);
		res[key] = true;
	}
	UNIT_ASSERT(203 == member::s_num);
	int i = 1;
	const member* node = rankSkipList->GetByRank(i);
	do {
		if (node != NULL)
		{
			member value = *node;
			//排行榜不可能重复
			if (res.find(value.getId()) != res.end())
			{
				LDEBUG("get del node. id=", value.id);
				UNIT_ASSERT(false);
			}
		//	printf("rank = %d   sum = %d, id = %d,chinese = %d,math = %d,english = %d\n",
		//		i, value.Sum(), value.getId(), value.getChinese(), value.getMath(), value.getEnglish());
			res[value.getId()] = true;
			i++;
			node = rankSkipList->GetByRank(i);
		}
	} while (node != NULL);
	printf("===========================================================================\n");
	for (int i = 1; i <= 50; i++)
	{
		rankSkipList->RemoveByRank(1);
	}
	UNIT_ASSERT(153 == member::s_num);
	i = 1;
	node = rankSkipList->GetByRank(i);
	do {
		if (node != NULL)
		{
			member value = *node;
		//	printf("rank = %d sum = %d, id = %d,chinese = %d,math = %d,english = %d\n",
		//		i, value.Sum(), value.getId(), value.getChinese(), value.getMath(), value.getEnglish());
			res[value.getId()] = true;
			i++;
			node = rankSkipList->GetByRank(i);
		}
	} while (node != NULL);
	printf("===========================================================================\n");
	std::vector<const member*> vec = rankSkipList->GetRangeByRank(10, 15);
	int rank = 10;
	for (auto v : vec)
	{
		member value = *v;
		//printf("rank=%d   id = %d,sum = %d,chinese = %d,math = %d,english = %d\n", rank,
		//	value.getId(), value.Sum(), value.getChinese(), value.getMath(), value.getEnglish());
		++rank;
	}
	UNIT_INFO("s3 num=%d", member::s_num);
}

void testFree()
{
	UNIT_ASSERT(member::s_num == 0);

	{
		RankSkipList<int, member> rank;
		UNIT_ASSERT(member::s_num == 1);
		rank.Insert(1, member(3, 10, 29, 39));
		rank.Insert(3, member(3, 10, 29, 39));
		rank.Insert(4, member(3, 10, 29, 39));
		UNIT_ASSERT(member::s_num == 4);
		rank.RemoveByRank(4);
		rank.RemoveByRank(0);
		rank.RemoveByRank(-1);
		UNIT_ASSERT(member::s_num == 4);
		rank.RemoveByRank(1);
		UNIT_ASSERT(member::s_num == 3);
		rank.RemoveByRank(2);
		UNIT_ASSERT(member::s_num == 2);
		rank.Clear();
		UNIT_ASSERT(member::s_num == 1);
	}
	UNIT_ASSERT(member::s_num == 0);
}
UNITTEST(mainrandskiplist)
{
  
    test1();
    test2();
	testFree();
}

//结果：
//          skiplist耗时 ： sorted_set耗时
//随机插入      12                  14
//随机插入+排名获取  1                好久！


UNITTEST(skiplistEffectTest)
{
	RankSkipList<int, std::pair<int, int>> skiplist(NUM_1000W);
	sorted_set<int, std::pair<int, int>, NUM_1000W> s;
#if 1
	{

		time_t startSec = time(nullptr);
		LDEBUG("start skiplist");
		for (uint32 i = 0; i < NUM_10W * 1; ++i)
		{
			int key = std::rand() % NUM_10W;
			int score = std::rand();
			skiplist.Insert(key, { key, score });
			skiplist.GetByRank(std::rand());
		}
		LDEBUG("end skiplist========================", time(nullptr) - startSec);
	}
	{

		time_t startSec = time(nullptr);
		LDEBUG("start sorted set");
		for (uint32 i = 0; i < NUM_10W * 1; ++i)
		{
			int key = std::rand() % 1000;
			int score = std::rand();
			s.insert(key, { key, score });
			s.rank(std::rand() % 1000);
		}
		LDEBUG("end sorted set========================", time(nullptr) - startSec);
	}
#endif // 0
#if 0
	{

		time_t startSec = time(nullptr);
		LDEBUG("start skiplist");
		for (uint32 i = 0; i < NUM_100W * 3; ++i)
		{
			int key = std::rand();
			int score = std::rand();
			skiplist.Insert(key, { key, score });
		}
		LDEBUG("end skiplist========================", time(nullptr) - startSec);
	}
	{

		time_t startSec = time(nullptr);
		LDEBUG("start sorted set");
		for (uint32 i = 0; i < NUM_100W * 3; ++i)
		{
			int key = std::rand();
			int score = std::rand();
			s.insert(key, { key, score });
		}
		LDEBUG("end sorted set========================", time(nullptr) - startSec);
}
#endif // 0

}

